package thimeeeee.Model;

import java.io.*;
//import thimeeeee.Skeleton;

//A pálya kétrehozására szolgáló osztály
public class LevelFactory {
    private Level level;
    private Game game;
    private Exit exit;

    public LevelFactory(Game g)
    {
//        Skeleton.Create("LevelFactory");
//        Skeleton.StartFunc("LevelFactory()");
        level = new Level(g);
        game = g;
        //Beállítjuk a a Fieldet, aminek segítségével elérhetjük a többit
//        Skeleton.EndFunc("LevelFactory()","void");
    }

    //eljárás ami a legutóbb betöltött pályát adja vissza --> restartLevelhez
    public Level GetLevel(){
        return level;
    }

	//Pálya beolvasása, és lekérése
    public Level GetLevel(int i) {
//		Skeleton.StartFunc("LevelFactroy.GetLevel("+i+")");
        StringBuilder contents = new StringBuilder();

        //a pálya legszélesebb sorának hossza
        int MaxWidth = 1;
        //a pálya legmagasabb oszlopának hossza (ez a falak miatt legalább 2)
        int MaxHeight = 2;

        int countBomb = 0;
        //a beolvasott térkép ideiglenesen egy karaktertömb formájában tárolódik
        //ebből generáljuk majd a megfelelő objektumokat
        char[][] charMap = new char[50][50];
        //tömb feltöltése alapértelmezett értékekkel
        for (int n = 0; n < 50; n++)
        {
            for (int m = 0; m < 50; m++)
            {
                charMap[n][m] = ' ';
            }
        }

        try {
      //use buffering, reading one line at a time
      //FileReader always assumes default encoding is OK!
             File f = new File("maps/" + String.valueOf(i)+".map");
             BufferedReader input =  new BufferedReader(new FileReader(f));
            try {
                //String line = null; //Sornál

                /*
                * readLine is a bit quirky :
                * it returns the content of a line MINUS the newline.
                * it returns null only for the END of the stream.
                * it returns an empty String if two newlines appear in a row.
                */

                int c;
                int k = 1;
                int j = 1;
                char kar;



                //pályával kapcsolatos információk beolvasása:
                //3 szám található az 1. sorban : életek száma, továbbjutáshoz szükséges gyémántok száma,
                                                //felhasználható bombák száma
                String info = input.readLine();
                String[] infos = info.split(" ");
                try
                {
                    game.userinfo.SetLives(Integer.parseInt(infos[0]));
                    game.userinfo.SetRequiredDiamonds(Integer.parseInt(infos[1]));
                    countBomb = Integer.parseInt(infos[2]);
                }
                catch (Exception ex)
                {
                    //akkor kerülünk ide, ha a beolvasott pálya formátuma hibás
                    //ekkor 1 életünk van, és 100 gyámánt szükséges a továbbjutáshoz
                    game.userinfo.SetLives(1);
                    game.userinfo.SetDiamonds(100);
                    countBomb = 0;
                    System.out.println("Nem támogatott formátum!");
                }

                //olvasás a file végéig : térkép beolvasása
//                String sor;
//                String[] karakterek;
//                while ((sor = input.readLine()) != null)
//                {
//                    karakterek = sor.split(" ");
//
//                    int test = 2 + 2;
//                }

                //sor és oszlop inicializálás.
                j = 0;
                k = 0;
                String[] sor = new String[50];
                while ((sor[j] = input.readLine()) != null)
                {
                    //páratlan sorok elejére "*  "
                    if (j % 2 == 0){
                        sor[j] = "*  " + sor[j];
                    }
                    else{
                        //ps sorok elejére "   "
                        sor[j] = "   " + sor[j];
                    }
                    j++;
                }

                //a leghosszabb sor hossza
                int maxLength = 0;
                //a leghosszabb sor indexe
                int iMaxLength = 0;

                int x = 0;
                while (sor[x] != null)
                {
                    //leghosszabb sor megkeresése
                    if (sor[x].length() > maxLength){
                        maxLength = sor[x].length();
                        iMaxLength = x;
                    }
                    x++;
                }

                //leghosszabb sort újra be kell állítani a whitespace-ek törlése miatt
                maxLength = 0;
                x = 0;
                while (sor[x] != null)
                {
                if (maxLength < sor[x].length()){
                        maxLength = sor[x].length();
                        iMaxLength = x;
                    }
                    x++;
                }

                x = 0;
                while (sor[x] != null)
                {
                    //a leghosszabb sorral ellenkező paritású sorok végére *
                    if ((iMaxLength % 2 ) != (x % 2)){
                        sor[x] = sor[x] + "*";
                    }
                    //szóközök eltűntetése
                    sor[x] = sor[x].replaceAll(" ", "");

                    

                    //karakterek kimásolása a charmap tömbbe
                    for (int n = 0; n < sor[x].length(); n++)
                    {
                        //x+2. sorba felvesszük a karaktereket (1. 2 sor fal lesz)
                        charMap[x + 2][n] = sor[x].charAt(n);
                    }
                    x++;
                }

                //a páros és páratlan sorok hosszának beállítása
                int ptlnLength = 0;
                int psLength = 0;
                for (int m = 0; m < x; m++)
                {
                    if ((m % 2 == 0) && (psLength < sor[m].length())){
                        psLength = sor[m].length();
                    }
                    else if ((m % 2 == 1) && (ptlnLength < sor[m].length())){
                        ptlnLength = sor[m].length();
                    }
                }

                MaxWidth = maxLength;
                //a belső játéktér magassága + 4 sor fal
                MaxHeight = x + 4;

                //a sorok hosszának egységesítése: minden páros sor psLength hosszú lesz, ptln pedig ptlnLength
                for (int n = 0; n < MaxHeight; n++)
                {
                    //adott paritású sor hossza
                    int length = (n % 2 == 0) ? psLength : ptlnLength;
                    for (int m = 0; m < length; m++)
                    {
                        if (charMap[n][m] == ' '){
                            charMap[n][m] = '*';
                        }
                    }
                }
                MaxWidth = (psLength > ptlnLength)? psLength : ptlnLength;
            }
              finally
              {
                input.close();
              }
        }
        catch (Exception ex)
        {
          System.out.println(ex.getMessage());
        }

        //itt már minden karakter valid, azaz a példányosításokat el tudjuk végezni
        //a példányosításokat a FieldFactory végzi el
        level.field = FieldFactory(charMap, MaxWidth, MaxHeight, countBomb);
        level.SetBombCount(countBomb);
        //kijárat beállítása
        level.exit = exit;
        level.maxHeight = MaxHeight;
        level.maxWidth = MaxWidth;

//        Skeleton.EndFunc("LevelFactroy.GetLevel("+i+")","level");
        return level;
	}

    //A Fieldek létrehozása
    //És kapcsolataik beállítása
    //Vissza adjuk a fieldet, aminek segítségével elérhetjük a többit (kiindulási mező)
    private Field FieldFactory(char[][] charMap, int maxWidth, int maxHeight, int bombCount)
    {
        //a létrehozott mezők ideiglenes tömbje, ez csak a kapcsolatok beállításához szükséges
       Field[][] fields = new Field[maxHeight][maxWidth];
       for(int k = 0; k < maxHeight; k++)
        {
            for(int j = 0; j < maxWidth; j++)
            {                 
                   System.out.print(charMap[k][j]);
            }
            System.out.println();
       }
       
       for(int k = 0; k < maxHeight; k++)
        {
            for(int j = 0; j < maxWidth; j++)
            {
                   switch(charMap[k][j])
                   {
                       case 'k':
                           fields[k][j] = new Field();

                           //egyik játékos
                           Player player1 = new Player(game);
                           fields[k][j].AddElement(player1);
                           //játékos beállítása player1-ként
                           game.player1 = player1;
                           break;
                       case 'l':
                           fields[k][j] = new Field();

                           //másik játékos
                           Player player2 = new Player(game);
                           fields[k][j].AddElement(player2);
                           //játékos beállítása player2-ként
                           game.player2 = player2;
                           break;
                       case '-':
                           fields[k][j] = new Field();

                           //üres mező
                           break;
                       case '#':
                           fields[k][j] = new Field();

                           //föld
                           fields[k][j].AddElement(new Soil());
                           break;
                       case 'g':
                           fields[k][j] = new Field();

                           //gránit
                           fields[k][j].AddElement(new Granite());
                           break;
                       case '*':
                           fields[k][j] = new Field();

                           //fal

                           fields[k][j].AddElement(new Wall());
                           break;
                       case 'e':
                           fields[k][j] = new Field();

                           //kijárat
                           exit = new Exit(level);
                           fields[k][j].AddElement(exit);
                           break;
                       case 'r':
                           fields[k][j] = new Field();

                           //kő
                           fields[k][j].AddElement(new Rock());
                           break;
                       case 'd':
                           fields[k][j] = new Field();

                           //gyémánt
                           fields[k][j].AddElement(new Diamond(game));
                           break;
                       case 'b':
                           fields[k][j] = new Field();

                           //bomba
                           fields[k][j].AddElement(new Bomb());
                           break;
                       //szörnyek
                       case '0':
                           fields[k][j] = new Field();

                           Beast beast = new Beast(game);
                           fields[k][j].AddElement(beast);
                           
                           //a proto teszteléséhez szükséges referencia
                           game.b0 = beast;
                           break;

                        case '1':
                           fields[k][j] = new Field();

                           Beast beast0 = new Beast(game);
                           beast0._isTracing = true;
                           fields[k][j].AddElement(beast0);
                           
                           //a proto teszteléséhez szükséges referencia
                           game.b1 = beast0;
                           break;

                        case '2':
                            fields[k][j] = new Field();

                           Beast beast2 = new Beast(game);
                           beast2._isReproducing = true;   
                           fields[k][j].AddElement(beast2);

                           //a proto teszteléséhez szükséges referencia
                           game.b2 = beast2;
                           break;

                        case '3':
                            fields[k][j] = new Field();

                           Beast beast3 = new Beast(game);
                           beast3._isReproducing = true;
                           beast3._isTracing = true;
                           fields[k][j].AddElement(beast3);

                           //a proto teszteléséhez szükséges referencia
                           game.b3 = beast3;
                           break;

                       case '4':
                           fields[k][j] = new Field();

                           Beast beast4 = new Beast(game);
                           beast4._isDiamond = true;
                           fields[k][j].AddElement(beast4);

                           //a proto teszteléséhez szükséges referencia
                           game.b4 = beast4;
                           break;

                       case '5':
                           fields[k][j] = new Field();

                           Beast beast5 = new Beast(game);
                           beast5._isDiamond = true;
                           beast5._isTracing = true;
                           fields[k][j].AddElement(beast5);

                           //a proto teszteléséhez szükséges referencia
                           game.b5 = beast5;
                           break;

                       case '6':
                           fields[k][j] = new Field();

                           Beast beast6 = new Beast(game);
                           beast6._isDiamond = true;
                           beast6._isReproducing = true;
                           fields[k][j].AddElement(beast6);

                           //a proto teszteléséhez szükséges referencia
                           game.b6 = beast6;
                           break;

                       case '7':
                           fields[k][j] = new Field();

                           Beast beast7 = new Beast(game);
                           beast7._isDiamond = true;
                           beast7._isTracing = true;
                           beast7._isReproducing = true;
                           fields[k][j].AddElement(beast7);

                           //a proto teszteléséhez szükséges referencia
                           game.b7 = beast7;
                           break;
                    }
                   
            }
        }

       //szomszédok beállítása
        for(int i = 0; i < maxHeight; i++)
        {
            for(int j = 0; j < maxWidth; j++)
            {
                if (fields[i][j] != null)
                {
                    //ha páros sor:
                    if (i % 2 == 0)
                    {
                        //ha nem a 0. sor, akkor van mező fölötte -> ennek beállítása
                        if (i > 0)
                        {
                            if (i > 1)
                            {
                                fields[i][j].SetNeighbor(fields[i-2][j], Direction.up);
                            }

                            //ha nem a 0. oszlop, akkor van mező balra -> ennek beállítása
                            if (j > 0)
                            {
                                fields[i][j].SetNeighbor(fields[i-1][j-1], Direction.upleft);
                            }

                            //ha nem az utolsó oszlop, akkor van mező jobbra -> ennek beállítása
                            if (j < maxWidth)
                            {
                                fields[i][j].SetNeighbor(fields[i-1][j], Direction.upright);
                            }
                        }
                        //ha nem az utolsó sor, akkor van mező alatta -> ennek beállítása
                        if (i < maxHeight -1 )
                        {
                            //ha nem az utolsó előtti sor, akkor van mező közvetlenül alatta
                            if (i < maxHeight - 2)
                            {
                                fields[i][j].SetNeighbor(fields[i+2][j], Direction.down);
                            }

                            //ha nem a 0. oszlop, akkor van mező balra -> ennek beállítása
                            if (j > 0)
                            {
                                fields[i][j].SetNeighbor(fields[i+1][j-1], Direction.downleft);
                            }

                            //ha nem az utolsó oszlop, akkor van mező jobbra -> ennek beállítása
                            if (j < maxWidth)
                            {
                                fields[i][j].SetNeighbor(fields[i+1][j], Direction.downright);
                            }
                        }
                    }
                    //ha páratlan
                    else
                    {
                    //ha nem a 0. sor, akkor van mező fölötte -> ennek beállítása
                        if (i > 0)
                        {
                            if (i > 1)
                            {
                                fields[i][j].SetNeighbor(fields[i-2][j], Direction.up);
                            }

                            //ha jobbra fölötte van mező...
                            if (j < maxWidth - 1)
                            {
                                fields[i][j].SetNeighbor(fields[i-1][j+1], Direction.upright);
                            }
                            fields[i][j].SetNeighbor(fields[i-1][j], Direction.upleft);

                        }
                        //ha nem az utolsó sor, akkor van mező alatta -> ennek beállítása
                        if (i < maxHeight - 1)
                        {
                            if (i < maxHeight - 2)
                            {
                                fields[i][j].SetNeighbor(fields[i+2][j], Direction.down);
                            }

                            //ha van még jobbra mező...
                            if (j < maxWidth - 1)
                            {
                                fields[i][j].SetNeighbor(fields[i+1][j+1], Direction.downright);
                            }
                            fields[i][j].SetNeighbor(fields[i+1][j], Direction.downleft);

                        }
                    }
                }
            }
        }

        return fields[0][0];

//        Field f1 = new Field();
//        Field f2 = new Field();
//        Field f3 = new Field();
//        Field f4 = new Field();
//        Field f5 = new Field();
//        Field f6 = new Field();
//        Field f7 = new Field();
//        Field f8 = new Field();
//        Field f9 = new Field();
//        /*
//            f1  f2  f3
//         *  f4  f5  f6
//         *  f7  f8  f9
//        */
//        f1.SetNeighbor(f2, Direction.right);
//        f1.SetNeighbor(f4, Direction.down);
//
//        f2.SetNeighbor(f1, Direction.left);
//        f2.SetNeighbor(f3, Direction.right);
//        f2.SetNeighbor(f5, Direction.down);
//
//        f3.SetNeighbor(f2, Direction.left);
//        f3.SetNeighbor(f6, Direction.down);
//
//        f4.SetNeighbor(f1, Direction.up);
//        f4.SetNeighbor(f5, Direction.right);
//        f4.SetNeighbor(f7, Direction.down);
//
//        f5.SetNeighbor(f2, Direction.up);
//        f5.SetNeighbor(f4, Direction.left);
//        f5.SetNeighbor(f6, Direction.right);
//        f5.SetNeighbor(f8, Direction.down);
//
//        f6.SetNeighbor(f3, Direction.up);
//        f6.SetNeighbor(f5, Direction.left);
//        f6.SetNeighbor(f9, Direction.down);
//
//        f7.SetNeighbor(f4, Direction.up);
//        f7.SetNeighbor(f8, Direction.right);
//
//        f8.SetNeighbor(f7, Direction.left);
//        f8.SetNeighbor(f5, Direction.up);
//        f8.SetNeighbor(f9, Direction.right);
//
//        f9.SetNeighbor(f8, Direction.left);
//        f9.SetNeighbor(f6, Direction.up);
//
//        switch (Skeleton.testEset)
//        {
//            case 2:
//                // move player
//                f5.AddElement(new Player(game));
//
//                //környező elemek elhelyezése
//
//                //alatta
//                String an = Skeleton.Ask("Mi van a jatekos alatt? [(G)yemant/(K)o/(B)omba/(F)old/(U)res mezo]",
//                        new String[] {"G", "K", "B", "F", "U"});
//                if (an.contentEquals("G")){
//                    f8.AddElement(new Diamond(game));
//                }
//                if (an.contentEquals("K")){
//                    f8.AddElement(new Rock());
//                }
//                if (an.contentEquals("B")){
//                    f8.AddElement(new Bomb());
//                }
//                if (an.contentEquals("F")){
//                    f8.AddElement(new Soil());
//                }
//
//                //fölötte
//                String an2 = Skeleton.Ask("Mi van a jatekos folott? [(G)yemant/(K)o/(B)omba/(F)old/(U)res mezo]",
//                        new String[] {"G", "K", "B", "F", "U"});
//                if (an2.contentEquals("G")){
//                    f2.AddElement(new Diamond(game));
//                }
//                if (an2.contentEquals("K")){
//                    f2.AddElement(new Rock());
//                }
//                if (an2.contentEquals("B")){
//                    f2.AddElement(new Bomb());
//                }
//                if (an2.contentEquals("F")){
//                    f2.AddElement(new Soil());
//                }
//
//                //jobbra
//                String an3 = Skeleton.Ask("Mi van a jatekostol jobbra? [(G)yemant/(K)o/(B)omba/(F)old/(U)res mezo]",
//                        new String[] {"G", "K", "B", "F", "U"});
//                if (an3.contentEquals("G")){
//                    f6.AddElement(new Diamond(game));
//                }
//                if (an3.contentEquals("K")){
//                    f6.AddElement(new Rock());
//                }
//                if (an3.contentEquals("B")){
//                    f6.AddElement(new Bomb());
//                }
//                if (an3.contentEquals("F")){
//                    f6.AddElement(new Soil());
//                }
//
//
//                //balra
//                String an4 = Skeleton.Ask("Mi van a jatekostol balra? [(G)yemant/(K)o/(B)omba/(F)old/(U)res mezo]",
//                        new String[] {"G", "K", "B", "F", "U"});
//                if (an4.contentEquals("G")){
//                    f4.AddElement(new Diamond(game));
//                }
//                if (an4.contentEquals("K")){
//                    f4.AddElement(new Rock());
//                }
//                if (an4.contentEquals("B")){
//                    f4.AddElement(new Bomb());
//                }
//                if (an4.contentEquals("F")){
//                    f4.AddElement(new Soil());
//                }
//
//                break;
//
//            case 3:
//                // falling, collapsing
//                f2.AddElement(new Rock());
//
//                //Megfelelő elemek hozzáadása a Fieldhez
//                //Tesztelő döntése alapján
//                String ans = Skeleton.Ask("Mi van a ko alatt? [(G)yemant/(K)o/(J)atekos/(B)omba/(F)old/(U)res mezo]",
//                        new String[] {"G", "K", "J", "B", "F", "U"});
//                if (ans.contentEquals("G")){
//                    f5.AddElement(new Diamond(game));
//                }
//                else if (ans.contentEquals("K")){
//                    f5.AddElement(new Rock());
//                }
//                else if (ans.contentEquals("J")){
//                    f5.AddElement(new Player(game));
//                }
//                else if (ans.contentEquals("B")){
//                    f5.AddElement(new Bomb());
//                }
//                else if (ans.contentEquals("F")){
//                    f5.AddElement(new Soil());
//                }
//                else if (ans.contentEquals("U")){
//                }
//                break;
//            case 4:
//                // robbanas
//                f5.AddElement(new Bomb());
//                String a = Skeleton.Ask("Mi van a bomba mellett? [(G)yemant, (F)old, (G)ranit, (Fa)l, (K)o, (J)atekos, (S)zorny]",
//                        new String[]{"G", "F", "Fa", "K", "J", "S"});
//                if (a.contentEquals("G")){
//                    f6.AddElement(new Diamond(game));
//                }
//                else if (a.contentEquals("F")){
//                    f6.AddElement(new Soil());
//                }
//                else if (a.contentEquals("Fa")){
//                    f6.AddElement(new Wall());
//                }
//                else if (a.contentEquals("K")){
//                    f6.AddElement(new Rock());
//                }
//                else if (a.contentEquals("J")){
//                    f6.AddElement(new Player(game));
//                }
//                else if (a.contentEquals("S")){
//                    f6.AddElement(new Beast());
//                }
//                break;
//            case 5:
//                // put bomb
//                f5.AddElement(new Player(game));
//                break;
//            case 6:
//                // beast meets player
//                f5.AddElement(new Player(game));
//                f6.AddElement(new Beast());
//                break;
//        }
//
//        //kiindulási mező beállítása
//        level.SetField(f1);
//
//        return f1;
        }
    }
